import * as BABYLON from "@babylonjs/core";
import * as GUI from "@babylonjs/gui";
import { AbstractDevice } from "../../AbstractDevice";
import {
  TWcsSceneDevice3d,
  TWcsSceneDeviceInfo,
  TWcsSceneDevice2d,
} from "../../../models";
import { KrData } from "../../KrData";
import { Task } from "../../../Task";
import { Arrow } from "./Arrow";
import { Label } from "./Label";
import { BaseDeviceControl2d } from "./BaseDeviceControl2d";

export class StandardDevice2d extends BaseDeviceControl2d {
  private _arrow?: Arrow;
  private _backgroundImage?: GUI.Image;
  private _label?: Label;
  private _text?: string;
  private _font1: string = 'Arial';
  private _fontSize1: number = 12;
  private _fontColor: string = '#111111';
  private _textBackground: string = 'transparent';
  private _textBorderSize: number = 0;
  private _textBorderColor: string = '#111111';
  private _textHAlignment: number = GUI.Control.HORIZONTAL_ALIGNMENT_LEFT;
  private _textVAlignment: number = GUI.Control.VERTICAL_ALIGNMENT_TOP;

  private _arrowDirection?: string;
  private _arrowColor?: string = 'white';

  constructor(data: TWcsSceneDevice2d) {
    super(data);
  }

  public init() {
    super.init();
    this.backgroundImage = this.data.backgroundImage;
    
    this._arrowDirection = this.data.arrowDirection;
    this._arrowColor = this.data.arrowColor;
    this.resetArrow();

    this._text = this.data.text;
    this._font1 = this.data.font || 'Arial';
    this._fontSize1 = this.data.fontSize;
    this._fontColor = this.data.fontColor || '#111111';
    this._textBackground = this.data.textBackground || 'transparent';
    this._textBorderSize = this.data.textBorderSize;
    this._textBorderColor = this.data.textBorderColor || this._fontColor;
    this._textHAlignment = this.data.textHAlignment;
    this._textVAlignment = this.data.textVAlignment;
    this.resetText();
  }

  public get text() {
    return this._text;
  }

  public set text(value: string | undefined) {
    this._text = value;
    this.resetText();
  }
  public get font(): string {
    return this._font1;
  }
  public set font(value: string) {
    this._font1 = value;
    this.resetText();
  }
  public get fontSize(): number {
    return this._fontSize1;
  }
  public set fontSize(value: number) {
    this._fontSize1 = value;
    this.resetText();
  }
  public get fontColor(): string {
    return this._fontColor;
  }
  public set fontColor(value: string) {
    this._fontColor = value;
    this.resetText();
  }
  public get textBackground(): string {
    return this._textBackground;
  }
  public set textBackground(value: string) {
    this._textBackground = value;
    this.resetText();
  }
  public get textBorderSize(): number {
    return this._textBorderSize;
  }
  public set textBorderSize(value: number) {
    this._textBorderSize = value;
    this.resetText();
  }
  public get textBorderColor(): string {
    return this._textBorderColor;
  }
  public set textBorderColor(value: string) {
    this._textBorderColor = value;
    this.resetText();
  }
  public get textHAlignment(): number {
    return this._textHAlignment;
  }
  public set textHAlignment(value: number) {
    this._textHAlignment = value;
    this.resetText();
  }

  public get backgroundImage(): GUI.Image | undefined {
    return this._backgroundImage;
  }
  public set backgroundImage(url: string | undefined) {
    if (this._backgroundImage) {
      this.removeControl(this._backgroundImage);
      this._backgroundImage = undefined;
    }
    if (url) {
      this._backgroundImage = new GUI.Image(
        this.id + "_image",
        this.data.backgroundImage
      );
      this._backgroundImage.stretch = GUI.Image.STRETCH_UNIFORM;
      this.addControl(this._backgroundImage);
    }
  }

  public get direction(): string | undefined {
    return this._arrowDirection;
  }
  public set direction(value: string| undefined) {
    this._arrowDirection = value;
    this.resetArrow();
  }

  public get arrowColor(): string | undefined {
    return this._arrowColor;
  }

  public set arrowColor(value: string | undefined) {
    this._arrowColor = value;
    this.resetArrow();
  }

  public update(info: KrData, colors: TWcsSceneDeviceInfo[]) {
    for (var color of colors) {
      if (this.evalInContext(info, color.infoExpression)) {
        this.backgroundColor =
          color.infoColor || this.data.backgroundColor || "transparent";
        return;
      }
    }
  }

  protected override setupAnimations(): Map<string, BABYLON.AnimationGroup> {
    return new Map<string, BABYLON.AnimationGroup>();
  }

  private resetText() {
    if(this._label) {
      this.removeControl(this._label);
      this._label = undefined;
    }

    if(this._text) {
      this._label = new Label(this.id + "_textBlock", this._text);
      this._label.fontFamily = this._font1;
      this._label.fontSize = this._fontSize1;
      this._label.fontColor = this._fontColor;
      this._label.background = this._textBackground;
      this._label.thickness = this._textBorderSize;
      this._label.color = this._textBorderColor;
      if (this._textVAlignment) {
        this._label.verticalAlignment = this._textVAlignment;
      }
      if (this._textHAlignment) {
        this._label.horizontalAlignment = this._textHAlignment;
      }
      this.addControl(this._label);
    }
  }

  private resetArrow() {
    if(this._arrow) {
      this.removeControl(this._arrow);
      this._arrow = undefined;
    }

    if(this._arrowDirection && this._arrowColor) {
      this._arrow = new Arrow(this.id + "_arrow");
      this._arrow.direction = this._arrowDirection;
      this._arrow.color = this._arrowColor;
      this.addControl(this._arrow);
    }
  }

  /**
   * 在指定对象的上下文中执行表达式
   * @param {any} o - 上下文对象，将被绑定到$变量
   * @param {string | undefined} expression - 要执行的表达式
   * @returns {any} 表达式的计算结果
   */
  private evalInContext(o: any, expression: string | undefined) {
    if (!expression) {
      return o;
    }
    try {
      // 创建一个函数，将对象o绑定到$变量，并执行表达式
      const evaluator = new Function("$", `return ${expression};`);
      return evaluator(o);
    } catch (error) {
      console.error("表达式执行错误:", error);
      return undefined;
    }
  }
}
